// /////////////////////////////////////////////////////////////////////////////
//
// Name:            AIPanel.h
// Author:          Michael Bartsch
//
// Desc :           This file contains the CAIPanel Class. This class
//                  can be used to directly manipulate the map of the AI Core.
//
// License:         Copyright (C) 2008-2009 Michael Bartsch
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the GNU General Public
//                  License as published by the Free Software Foundation,
//                  either version 3 of the License, or (at your option) any
//                  later version.
//
//                  This program is distributed in the hope that it will be
//                  useful, but WITHOUT ANY WARRANTY; without even the implied
//                  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//                  PURPOSE. See the GNU General Public License for more
//                  details.
//
//                  You should have received a copy of the GNU General Public
//                  License along with this program. If not, see
//                  <http://www.gnu.org/licenses/>.
//
// /////////////////////////////////////////////////////////////////////////////

// Include required header file(s).
#include "AIPanel.h"


// CAIPanel Events. - [ BEGIN ]
BEGIN_EVENT_TABLE(CAIPanel, wxPanel)
   EVT_PAINT(CAIPanel::onPaint)
   EVT_SCROLLWIN(CAIPanel::onScroll)
   EVT_MOUSE_EVENTS(CAIPanel::onMouseEvent)
END_EVENT_TABLE()
// CAIPanel Events. - [ END ]


// CAIPanel.
// Constructor.
CAIPanel::CAIPanel(wxWindow *parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(768,672), wxVSCROLL | wxHSCROLL | wxALWAYS_SHOW_SB |wxSUNKEN_BORDER)
{
   // Set internal variables.
   frameParent = (CAIFrame*)parent;
   pAICore = CAICore::Instance();

   bufferImage = 0;
   bufferBitmap = 0;

   panelState = AIP_Start;

   adjustScrollbars();
}

// Updates the paintable buffer.
void CAIPanel::updateBuffer()
{
   // Initialise and set variables.
   wxSize clientSize = GetClientSize();

   if(bufferImage != 0)      delete bufferImage;
   if(bufferBitmap != 0)     delete bufferBitmap;

   // Draw the cells on a new image.
   bufferImage = new wxImage((clientSize.x+32), (clientSize.y+32));

   for(int y = 0; y < (clientSize.y+32)/32; y++)
   {
      for(int x = 0; x < (clientSize.x+32)/32; x++)
      {
         // Are we within the boundaries?
         if(x+GetScrollPos(wxHORIZONTAL) >= 0 && x+GetScrollPos(wxHORIZONTAL) < 100 &&
            y+GetScrollPos(wxVERTICAL) >= 0 && y+GetScrollPos(wxVERTICAL) < 100)
         {
            // Determine the state of the node.
            switch(pAICore->getNode(x+GetScrollPos(wxHORIZONTAL), y+GetScrollPos(wxVERTICAL))->state)
            {
               case ASN_Walkable:

                  for(int i = 0; i < 32; i++)
                  {
                     for(int j = 0; j < 32; j++)
                     {
                        bufferImage->SetRGB(x*32+j, y*32+i, 255, 255, 255);
                     }
                  }

                  break;

               case ASN_Unwalkable:

                  for(int i = 0; i < 32; i++)
                  {
                     for(int j = 0; j < 32; j++)
                     {
                        bufferImage->SetRGB(x*32+j, y*32+i, 0, 0, 0);
                     }
                  }

                  break;

               case ASN_Unknown:

                  for(int i = 0; i < 32; i++)
                  {
                     for(int j = 0; j < 32; j++)
                     {
                        bufferImage->SetRGB(x*32+j, y*32+i, 230, 230, 230);
                     }
                  }

                  break;
            }

            // Draw the borders of the cells.
            for(int i = 0; i < 32; i++)
            {
               for(int j = 0; j < 32; j++)
               {
                  if(i == 0 || i == 31 || j == 0 || j == 31)
                    bufferImage->SetRGB(x*32+j, y*32+i, 206, 206, 206);
               }
            }

            // Is this is a special location?
            if(x+GetScrollPos(wxHORIZONTAL) == pAICore->getTargetX() &&
               y+GetScrollPos(wxVERTICAL) == pAICore->getTargetY())
            {
               for(int i = 0; i < 32; i++)
               {
                  for(int j = 0; j < 32; j++)
                  {
                     if(abs(16-i)+abs(16-j) < 8)
                       bufferImage->SetRGB(x*32+j, y*32+i, 255, 0, 0);
                  }
               }
            }

            if(x+GetScrollPos(wxHORIZONTAL) == pAICore->getStartX() &&
               y+GetScrollPos(wxVERTICAL) == pAICore->getStartY())
            {
               for(int i = 0; i < 32; i++)
               {
                  for(int j = 0; j < 32; j++)
                  {
                     if(abs(16-i)+abs(16-j) < 8)
                       bufferImage->SetRGB(x*32+j, y*32+i, 0, 255, 0);
                  }
               }
            }
         }
      }
   }

   // Convert the image to an bitmap.
   bufferBitmap = new wxBitmap(*bufferImage, -1);

   // Here we ask for a refresh.
   Refresh();
}

// Adjusts the scrollbars of the panel.
void CAIPanel::adjustScrollbars()
{
   wxSize clientSize = GetClientSize();

   SetScrollbar(wxHORIZONTAL, 39, clientSize.GetWidth()/32, 100, true);
   SetScrollbar(wxVERTICAL, 39, clientSize.GetHeight()/32, 100, true);

   updateBuffer();
}

// Event Functions. - [ BEGIN ]
void CAIPanel::onPaint(wxPaintEvent &event)
{
   // Here we're going to create the paint DC.
   wxBufferedPaintDC *PanelDC = new wxBufferedPaintDC(this);

   // Paint on the DC.
   if(bufferBitmap != NULL)
     PanelDC->DrawBitmap(*bufferBitmap, 0, 0, false);

   // Tidy code up.
   delete PanelDC;
}

void CAIPanel::onScroll(wxScrollWinEvent &event)
{
    // Which scrollbar has been activated?
    int orientation = event.GetOrientation();

    // Determine the event.
    if(event.GetEventType() == wxEVT_SCROLLWIN_LINEUP)
      SetScrollPos(orientation, GetScrollPos(orientation)-1, true);

    else if(event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP)
      SetScrollPos(orientation, GetScrollPos(orientation)-10, true);

    else if(event.GetEventType() == wxEVT_SCROLLWIN_TOP)
      SetScrollPos(orientation, 0, true);

    else if(event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN)
      SetScrollPos(orientation, GetScrollPos(orientation)+1, true);

    else if(event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN)
      SetScrollPos(orientation, GetScrollPos(orientation)+10, true);

    else if(event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM)
      SetScrollPos(orientation, GetScrollRange(orientation), true);

    else if(event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK)
      SetScrollPos(orientation, event.GetPosition(), true);

    updateBuffer();
}

void CAIPanel::onMouseEvent(wxMouseEvent &event)
{
    // Determine event.
    if(event.m_leftDown)
    {
       // Determine the action.
       switch(panelState)
       {
          case AIP_Start: // Set the start position.

             pAICore->setStartLocation((event.GetX()/32)+GetScrollPos(wxHORIZONTAL), (event.GetY()/32)+GetScrollPos(wxVERTICAL));
             frameParent->update();
             break;

          case AIP_Target: // Set the target position.

             pAICore->setTargetLocation((event.GetX()/32)+GetScrollPos(wxHORIZONTAL), (event.GetY()/32)+GetScrollPos(wxVERTICAL));
             frameParent->update();
             break;

          case AIP_Walkable: // Set walkable nodes.

             pAICore->setNodeState((event.GetX()/32)+GetScrollPos(wxHORIZONTAL), (event.GetY()/32)+GetScrollPos(wxVERTICAL), ASN_Walkable);
             updateBuffer();
             break;

          case AIP_Unwalkable: // Set unwalkable nodes.

             pAICore->setNodeState((event.GetX()/32)+GetScrollPos(wxHORIZONTAL), (event.GetY()/32)+GetScrollPos(wxVERTICAL), ASN_Unwalkable);
             updateBuffer();
             break;

          case AIP_Unknown: // Set unknown nodes.

             pAICore->setNodeState((event.GetX()/32)+GetScrollPos(wxHORIZONTAL), (event.GetY()/32)+GetScrollPos(wxVERTICAL), ASN_Unknown);
             updateBuffer();
             break;
       }
    }

    // Update the coordinates in the status bar.
    int x = (event.GetX()/32)+GetScrollPos(wxHORIZONTAL);
    int y = (event.GetY()/32)+GetScrollPos(wxVERTICAL);

    if(x >= 0 && x < 100 && y >= 0 && y < 100)
    {
       wxString stringX;
       stringX.Printf(_T("X: %d"), x);
       frameParent->SetStatusText(stringX, 1);

       wxString stringY;
       stringY.Printf(_T("Y: %d"), y);
       frameParent->SetStatusText(stringY, 2);
    }
}
// Event Functions. - [ END ]

// Set Functions - [ BEGIN ]
void CAIPanel::setState(int state)
{
   panelState = state;
}
// Set Functions - [ END ]

// End of File
